package com.dji.sdk.mqtt;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.integration.mqtt.support.MqttHeaders;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;

import javax.annotation.Resource;
import java.util.UUID;

/**
 * MQTT客户端配置类。
 * 此类负责配置MQTT连接，包括入站消息适配器和出站消息处理器。
 * 它是DJI云API与MQTT服务器之间通信的核心配置类，处理所有与无人机的消息交换。
 * 
 * 入站消息：从MQTT服务器到应用程序的消息，例如从无人机接收的状态更新等。
 * 出站消息：从应用程序到MQTT服务器的消息，例如向无人机发送的命令等。
 * 
 * @author sean.zhou
 * @date 2021/11/10
 * @version 0.1
 */
@Configuration
@IntegrationComponentScan
public class MqttConfiguration {

    /**
     * 日志记录器，用于记录MQTT配置和消息处理过程中的信息
     */
    private static final Logger log = LoggerFactory.getLogger(MqttConfiguration.class);

    /**
     * 入站消息主题配置，通过application.yml中的cloud-sdk.mqtt.inbound-topic属性设置
     * 这些主题定义了应用程序需要订阅哪些MQTT主题以接收消息
     */
    @Value("${cloud-sdk.mqtt.inbound-topic: }")
    private String inboundTopic;

    /**
     * MQTT客户端工厂，用于创建MQTT客户端
     */
    @Resource
    private MqttPahoClientFactory mqttClientFactory;

    /**
     * 入站消息通道，用于处理从MQTT服务器接收的消息
     */
    @Resource(name = ChannelName.INBOUND)
    private MessageChannel inboundChannel;

    /**
     * 配置入站消息适配器。
     * 此方法创建一个MQTT入站消息适配器，用于接收来自MQTT服务器的消息。
     * 
     * @return MqttPahoMessageDrivenChannelAdapter 入站消息适配器实例
     */
    @Bean
    public MqttPahoMessageDrivenChannelAdapter mqttInbound() {
        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(
                UUID.randomUUID().toString(), mqttClientFactory, inboundTopic.split(","));
        DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter();
        // 统一使用字节类型处理消息
        converter.setPayloadAsBytes(true);
        adapter.setConverter(converter);
        adapter.setQos(1);  // 设置服务质量级别为1，确保消息至少送达一次
        adapter.setOutputChannel(inboundChannel);
        return adapter;
    }

    /**
     * 配置出站消息处理器。
     * 此方法创建一个MQTT出站消息处理器，用于向MQTT服务器发送消息。
     * 
     * @return MessageHandler 出站消息处理器实例
     */
    @Bean
    @ServiceActivator(inputChannel = ChannelName.OUTBOUND)
    public MessageHandler mqttOutbound() {
        MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(
                UUID.randomUUID().toString(), mqttClientFactory);
        DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter();
        // 统一使用字节类型处理消息
        converter.setPayloadAsBytes(true);

        messageHandler.setAsync(true);  // 设置为异步发送消息
        messageHandler.setDefaultQos(0);  // 默认服务质量级别为0，最多发送一次
        messageHandler.setConverter(converter);
        return messageHandler;
    }

    /**
     * 配置默认的入站消息处理器。
     * 此方法创建一个默认的消息处理器，用于处理那些没有特定处理逻辑的消息。
     * 
     * @return MessageHandler 默认消息处理器实例
     */
    @Bean
    @ServiceActivator(inputChannel = ChannelName.DEFAULT)
    public MessageHandler defaultInboundHandler() {
        return message -> {
            log.info("The default channel does not handle messages." +
                    "\nTopic: " + message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC) +
                    "\nPayload: " + message.getPayload() + "\n");
        };
    }
}
